﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Titan.Serialization
{
    public static class Bit7Encoding
    {
        public static byte[] EncodeInt32(int value)
        {
            List<byte> list = new List<byte>();
            uint num = (uint)value;
            while (num >= 0x80)
            {
                list.Add((byte)(num | 0x80));
                num >>= 7;
            }
            list.Add((byte)num);
            return list.ToArray();
        }

        public static int DecodeInt32(byte[] value, int startIndex)
        {
            if (null == value || 0 == value.Length)
                throw new ArgumentNullException("value");
            if (startIndex >= value.Length)
                throw new ArgumentOutOfRangeException("startIndex");

            uint b;
            uint num = 0;
            int shift = 0;
            do
            {
                if (shift > 64)
                    throw new FormatException();
                if (startIndex >= value.Length)
                    throw new FormatException();

                b = value[startIndex];
                num |= (b & 0x7f) << shift;
                shift += 7;
                startIndex++;
            }
            while ((b & 0x80) != 0);
            return (int)num;
        }

        public static void Write7BitEncodedInt32(Stream stream, int value)
        {
            if (null == stream)
                throw new ArgumentNullException("stream");
            uint num = (uint)value;

            while (num >= 0x80)
            {
                stream.WriteByte((byte)(num | 0x80));
                num = num >> 7;
            }
            stream.WriteByte((byte)num);
        }

        public static int Read7BitEncodedInt32(Stream stream)
        {
            if (null == stream)
                throw new ArgumentNullException("stream");

            int b;
            uint num = 0;
            int shift = 0;
            do
            {
                if (shift > 32)
                    throw new FormatException();

                b = stream.ReadByte();
                if (b < 0)
                    throw new FormatException();
                num |= (UInt32)((b & 0x7f) << shift);
                shift += 7;
            }
            while ((b & 0x80) != 0);
            return (int)num;
        }

        public static void Write7BitEncodedInt32(BinaryWriter writer, int value)
        {
            if (null == writer)
                throw new ArgumentNullException("writer");
            uint num = (uint)value;

            while (num >= 0x80)
            {
                writer.Write((byte)(num | 0x80));
                num = num >> 7;
            }
            writer.Write((byte)num);
        }

        public static int Read7BitEncodedInt32(BinaryReader reader)
        {
            if (null == reader)
                throw new ArgumentNullException("reader");

            byte b;
            uint num = 0;
            int shift = 0;
            do
            {
                if (shift > 32)
                    throw new FormatException();

                b = reader.ReadByte();
                if (b < 0)
                    throw new FormatException();
                num |= (UInt32)((b & 0x7f) << shift);
                shift += 7;
            }
            while ((b & 0x80) != 0);
            return (int)num;
        }

    }
}
